package server

import (
	"edata-hub/pkg/raft"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	gonanoid "github.com/matoous/go-nanoid"
	"io"
	"net/http"
)

func (m *Master) InitExHttpServices() {
	m.RServer.RegisterHttpService("/components/getcomponents", m.GetComponents, "GET")
	m.RServer.RegisterHttpService("/components/getcompmodes", m.GetCompModes, "GET")
	m.RServer.RegisterHttpService("/components/getcomproles", m.GetCompRoles, "GET")
	m.RServer.RegisterHttpService("/components/getcompconfigs", m.GetCompConfigs, "GET")
	m.RServer.RegisterHttpService("/components/policysubmit", m.PolicySubmit, "POST")
	m.RServer.RegisterHttpService("/clusters/getclusters", m.GetClusters, "GET")
	m.RServer.RegisterHttpService("/clusters/getnodes", m.GetNodes, "GET")
	m.RServer.RegisterHttpService("/clusters/getnodestatus", m.GetNodeStatus, "GET")
	m.RServer.RegisterHttpService("/clusters/getprogress", m.GetProgress, "GET")
	m.RServer.RegisterHttpService("/clusters/getroles", m.GetRoles, "GET")
	m.RServer.RegisterHttpService("/clusters/startworker", m.StartClusterWorker, "GET")
	m.RServer.RegisterHttpService("/clusters/stopworker", m.StopClusterWorker, "GET")
	m.RServer.RegisterHttpService("/clusters/startdatacomp", m.StartDataComp, "GET")
	m.RServer.RegisterHttpService("/clusters/stopdatacomp", m.StopDataComp, "GET")
	m.RServer.RegisterHttpService("/clusters/websocketconn", m.WebSocketConn, "GET")
}

func (m *Master) PolicySubmit(gc *gin.Context) {
	policy, readReqBodyErr := io.ReadAll(gc.Request.Body)
	if readReqBodyErr != nil {
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": readReqBodyErr.Error(),
		})
		return
	}
	//TODO 检查policy是否合法
	clusterId, _ := gonanoid.Nanoid()
	params := make(map[string]string)
	params["policy"] = string(policy)
	params["clusterId"] = clusterId
	oce := raft.CommandEntry{
		Name:   CLUSTER_INSTALL,
		Params: params,
	}
	//调用优化器，对初始命令进行优化，得到多个子命令
	rces, _ := m.RServer.CommandOptimizer(oce)
	//http情况下，异步执行命令，rpc情况下，客户端需要阻塞
	go func() {
		for index, rce := range rces {
			method, ok := m.RServer.Commands[rce.Name]
			if !ok {
				m.RServer.Msg.Info("command %s is not existed", rce.Name)
				break
			} else {
				m.RServer.Msg.Info("command %s:%v is running", rce.Name, rce.Params)
				ret := method(rce.Params)
				wsWriteData := fmt.Sprintf("{\"clusterId\":\"%s\",\"index\":%d,\"status\":%d}", rce.Params["clusterId"], index, ret.Status)
				if index == 0 {
					//第一个命令时创建进度的命令，所以不需要更新
					continue
				}
				m.UpdateProgressStatus(rce.Params["clusterId"], index-1, ret.Status)
				m.WriteWSMsg([]byte(wsWriteData))
				if ret.Status == -1 {
					m.RServer.Msg.Error("command %s execute fail:%s", rce.Name, ret.Msg)
					break
				} else {
					m.RServer.Msg.Info("command %s execute success", rce.Name)
				}
			}
		}
	}()
	gc.JSON(http.StatusOK, gin.H{
		"msg": "提交成功",
	})
	return
}

func (m *Master) GetComponents(gc *gin.Context) {
	empty := make(map[string]string)
	oce := raft.CommandEntry{
		Name:       DATACOMP_SEARCH,
		Params:     empty,
		ExecStatus: 0,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"status": ret.Status,
			"msg":    ret.Msg,
			"result": ret.Data,
		})
	}
}

func (m *Master) GetCompModes(gc *gin.Context) {
	comp := gc.Query("comp")
	params := make(map[string]string)
	params["comp"] = comp
	oce := raft.CommandEntry{
		Name:   DATACOMP_MODE_SEARCH,
		Params: params,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"success": ret.Status,
			"msg":     ret.Msg,
			"result":  ret.Data,
		})
	}
}

func (m *Master) GetCompRoles(gc *gin.Context) {
	comp := gc.Query("comp")
	mode := gc.Query("[sa]mode")
	params := make(map[string]string)
	params["comp"] = comp
	params["[sa]mode"] = mode
	oce := raft.CommandEntry{
		Name:   DATACOMP_ROLE_SEARCH,
		Params: params,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"success": ret.Status,
			"msg":     ret.Msg,
			"result":  ret.Data,
		})
	}
}

func (m *Master) GetCompConfigs(gc *gin.Context) {
	comp := gc.Query("comp")
	mode := gc.Query("[sa]mode")
	params := make(map[string]string)
	params["comp"] = comp
	params["[sa]mode"] = mode
	oce := raft.CommandEntry{
		Name:   DATACOMP_CONFIG_SEARCH,
		Params: params,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"success": ret.Status,
			"msg":     ret.Msg,
			"result":  ret.Data,
		})
	}
}

func (m *Master) GetClusters(gc *gin.Context) {
	empty := make(map[string]string)
	oce := raft.CommandEntry{
		Name:       CLUSTER_SEARCH,
		Params:     empty,
		ExecStatus: 0,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"status": ret.Status,
			"msg":    ret.Msg,
			"result": ret.Data,
		})
	}
}

func (m *Master) GetNodes(gc *gin.Context) {
	clusterId := gc.Query("clusterId")
	params := make(map[string]string)
	params["clusterId"] = clusterId
	oce := raft.CommandEntry{
		Name:   NODES_SEARCH,
		Params: params,
	}
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		respMsg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": respMsg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"status": ret.Status,
			"msg":    ret.Msg,
			"result": ret.Data,
		})
	}
}

func (m *Master) GetNodeStatus(gc *gin.Context) {
	ip := gc.Query("ip")
	params := make(map[string]string)
	params["ip"] = ip
	oce := raft.CommandEntry{
		Name:   NODE_STATUS_SEARCH,
		Params: params,
	}
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"status": ret.Status,
			"msg":    ret.Msg,
			"result": ret.Data,
		})
	}

}

func (m *Master) GetProgress(gc *gin.Context) {
	clusterId := gc.Query("clusterId")
	params := make(map[string]string)
	params["clusterId"] = clusterId
	ps_ce := raft.CommandEntry{
		Name:   PROGRESS_SEARCH,
		Params: params,
	}
	rces, optimizeErr := m.RServer.CommandOptimizer(ps_ce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		respMsg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": respMsg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"status": ret.Status,
			"msg":    ret.Msg,
			"result": ret.Data,
		})
	}
}

func (m *Master) StartClusterWorker(gc *gin.Context) {
	addr := gc.Query("addr")
	auths := gc.Query("auths")
	params := make(map[string]string)
	params["addr"] = addr
	params["auths"] = auths
	oce := raft.CommandEntry{
		Name:   WORKER_START,
		Params: params,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"success": ret.Status,
			"msg":     ret.Msg,
			"result":  ret.Data,
		})
	}
}

func (m *Master) StopClusterWorker(gc *gin.Context) {
	addr := gc.Query("addr")
	auths := gc.Query("auths")
	comp := gc.Query("comp")
	params := make(map[string]string)
	params["addr"] = addr
	params["auths"] = auths
	params["comp"] = comp
	oce := raft.CommandEntry{
		Name:   WORKER_STOP,
		Params: params,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"success": ret.Status,
			"msg":     ret.Msg,
			"result":  ret.Data,
		})
	}
}

func (m *Master) StartDataComp(gc *gin.Context) {
	addr := gc.Query("addr")
	comp := gc.Query("comp")
	roles := gc.Query("roles")
	params := make(map[string]string)
	params["addr"] = addr
	params["roles"] = roles
	params["comp"] = comp
	oce := raft.CommandEntry{
		Name:   ROLE_START,
		Params: params,
	}
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	go func() {
		for _, rce := range rces {
			method, ok := m.RServer.Commands[rce.Name]
			if !ok {
				m.RServer.Msg.Error("command %s is not existed", rce.Name)
				break
			} else {
				m.RServer.Msg.Info("command %s:%v is running", rce.Name, rce.Params)
				ret := method(rce.Params)
				//wsWriteData:=fmt.Sprintf("{\"ip\":\"%s\",\"role\":\"%s\",\"status\":%d}")
				//m.WriteWSMsg([]byte(ret.Data))

				if ret.Status == -1 {
					m.RServer.Msg.Error("command %s execute fail:%s", rce.Name, ret.Msg)
					break
				} else {
					m.RServer.Msg.Info("command %s execute success", rce.Name)
				}
			}
		}
	}()
	gc.JSON(http.StatusOK, gin.H{
		"msg": "提交成功",
	})
	return
}

func (m *Master) StopDataComp(gc *gin.Context) {
	addr := gc.Query("addr")
	roles := gc.Query("roles")
	comp := gc.Query("comp")
	params := make(map[string]string)
	params["addr"] = addr
	params["roles"] = roles
	params["comp"] = comp
	oce := raft.CommandEntry{
		Name:   ROLE_STOP,
		Params: params,
	}
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	go func() {
		for _, rce := range rces {
			method, ok := m.RServer.Commands[rce.Name]
			if !ok {
				m.RServer.Msg.Error("command %s is not existed", rce.Name)
				break
			} else {
				m.RServer.Msg.Info("command %s:%v is running", rce.Name, rce.Params)
				ret := method(rce.Params)
				//m.WriteWSMsg([]byte(ret.Data))
				if ret.Status == -1 {
					m.RServer.Msg.Error("command %s execute fail:%s", rce.Name, ret.Msg)
					break
				} else {
					m.RServer.Msg.Info("command %s execute success", rce.Name)
				}
			}
		}
	}()
	gc.JSON(http.StatusOK, gin.H{
		"msg": "提交成功",
	})
}

func (m *Master) GetRoles(gc *gin.Context) {
	clusterId := gc.Query("clusterId")
	ip := gc.Query("ip")
	comp := gc.Query("comp")
	params := make(map[string]string)
	params["clusterId"] = clusterId
	params["ip"] = ip
	params["comp"] = comp
	oce := raft.CommandEntry{
		Name:   ROLE_SEARCH,
		Params: params,
	}
	//调用优化器，将客户端提交的命令进一步优化
	rces, optimizeErr := m.RServer.CommandOptimizer(oce)
	if optimizeErr != nil {
		gc.JSON(http.StatusInternalServerError, gin.H{
			"msg": optimizeErr.Error(),
		})
	}
	method, ok := m.RServer.Commands[rces[0].Name]
	if !ok {
		resp_msg := "command is not existed"
		gc.JSON(http.StatusBadRequest, gin.H{
			"msg": resp_msg,
		})
	} else {
		ret := method(rces[0].Params)
		gc.JSON(http.StatusOK, gin.H{
			"success": ret.Status,
			"msg":     ret.Msg,
			"result":  ret.Data,
		})
	}
}

func (m *Master) WebSocketConn(gc *gin.Context) {
	conn, uErr := m.RServer.WSUpgrader.Upgrade(gc.Writer, gc.Request, nil)
	if uErr != nil {
		m.Msg.Error("can not upgrade connection,msg:%s", uErr.Error())
		return
	}
	conn.SetCloseHandler(func(code int, text string) error {
		m.Msg.Info("%s's websocket has been disconnected from the server", gc.Request.RemoteAddr)
		delete(m.RServer.WSConnPool, conn.RemoteAddr().String())
		return nil
	})
	m.RServer.WSConnPool[conn.RemoteAddr().String()] = conn
}

func (m *Master) WriteWSMsg(data []byte) {
	shouldDeletedWSConns := make([]string, 0)
	for addr, wsconn := range m.RServer.WSConnPool {
		m.RServer.Mutex.Lock()
		wsWriteErr := wsconn.WriteMessage(websocket.TextMessage, []byte(data))
		m.RServer.Mutex.Unlock()
		if wsWriteErr != nil {
			shouldDeletedWSConns = append(shouldDeletedWSConns, addr)
			m.RServer.Msg.Error("can not write to ws conn:%v", wsWriteErr)
			continue
		}
	}
	for _, addr := range shouldDeletedWSConns {
		delete(m.RServer.WSConnPool, addr)
	}
}

func (w *Worker) InitWorkerHttpServices() {
	w.RegisterWorkerHttpService("/ping", w.Ping, "GET")
}

func (w *Worker) RegisterWorkerHttpService(url string, method func(gc *gin.Context), rtype string) {
	switch rtype {
	case "GET":
		w.HttpServer.GET(url, method)
	case "POST":
		w.HttpServer.POST(url, method)
	default:
		w.HttpServer.GET(url, method)
	}
}

func (w *Worker) Ping(gc *gin.Context) {
	gc.JSON(http.StatusOK, gin.H{
		"result": "You have got a ping message",
	})
}
